// ignore_for_file: avoid_print

import 'package:dio/dio.dart';
import 'package:flujs/extension/fetch.dart';
import 'package:flujs/extension/xhr.dart';
import 'package:flujs/flujs.dart';
import 'package:flutter_test/flutter_test.dart';
// ignore: depend_on_referenced_packages
import 'package:http/http.dart' as http;
import 'package:http_interceptor/http_interceptor.dart';
import 'package:flujs_jsc/jsc.dart' as jsc;
import 'package:flujs_qjs/qjs.dart' as qjs;

void main() {
  runEngine(JSFRuntime rt, {http.Client? client}) async {
    var ctx = rt.newContext()..loadExtension(xhr: client == null);
    if (client != null) {
      ctx.extension
          ?.chain(XhrExtension(ctx, client_: client).chain(FetchExtension(ctx)))
          .load();
    }
    var post = await ctx.evalAsync(
      '''fetch('http://localhost:3000/posts/1/')''',
      timeout: const Duration(seconds: 3),
    );
    // TODO: dart 侧可以获取 fetch response，并且执行 json(), text()
    print('[post] $post, ${post.isString()}');
    expect(post.hasProperty('ok'), true);
    final jstr = await ctx.runPromise(
      post.getProperty('json').callAsFunction(),
    );
    print('[jstr] ${jstr.jsonString()}');
    final headers =
        post.getProperty('headers').getProperty('entries').callAsFunction();
    print('[headers] ${headers.isArray()}');
    final len = headers.getProperty('length').toNumber();
    for (var i = 0; i < len; i++) {
      final kv = headers.getPropertyAtIndex(i);
      print('[kv] ${kv.isArray()}');
    }
  }

  test('jsc_dio', () async {
    var rt = jsc.getJSFRuntime();
    await runEngine(rt, client: DioAdapter());
  });
  test('jsc_default', () async {
    var rt = jsc.getJSFRuntime();
    await runEngine(rt, client: HttpPackageAdapter());
  });
  test('jsc_http', () async {
    var rt = jsc.getJSFRuntime();
    await runEngine(rt);
  });
  test('jsc_interceptor', () async {
    final client = InterceptedClient.build(
      interceptors: [LoggingInterceptor()],
    );
    var rt = jsc.getJSFRuntime();
    await runEngine(rt, client: client);
  });
  test('qjs_interceptor', () async {
    final client = InterceptedClient.build(
      interceptors: [LoggingInterceptor()],
    );
    var rt = qjs.getJSFRuntime();
    await runEngine(rt, client: client);
  });
}

class DioAdapter extends http.BaseClient {
  final dio = Dio();

  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) async {
    final response = await dio.requestUri(
      request.url,
      options: Options(headers: request.headers),
    );
    return http.StreamedResponse(response.data, response.statusCode ?? 400);
  }
}

class HttpPackageAdapter extends http.BaseClient {
  final http.Client _inner = http.Client();
  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) {
    return _inner.send(request);
  }
}

class LoggingInterceptor implements InterceptorContract {
  @override
  Future<http.BaseRequest> interceptRequest({
    required http.BaseRequest request,
  }) {
    print('[Logging] 😯 request: make cache or something.');
    return Future.value(request);
  }

  @override
  Future<http.BaseResponse> interceptResponse({
    required http.BaseResponse response,
  }) {
    print('[Logging] 😊 response: make cache or something.');
    return Future.value(response);
  }

  @override
  Future<bool> shouldInterceptRequest() {
    return Future.value(true);
  }

  @override
  Future<bool> shouldInterceptResponse() {
    return Future.value(true);
  }
}
